-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ 3주차 기본/심화 과제 ] 3주차 과제 제출 #5
base: main
Are you sure you want to change the base?
Conversation
…GeunOh into week3/assign1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
context API도 활용하고 theme도 야무지게 잘 사용했다! 코드가 전체적으로 다 깔끔하넹
항상 형근이 코드 보고 많이 배워가💪🏻!!
다음주차 과제도 기대할겡 아자자!
const ImgChunks = { | ||
IMG_1, | ||
IMG_2, | ||
IMG_3, | ||
IMG_4, | ||
IMG_5, | ||
IMG_6, | ||
IMG_7, | ||
IMG_8, | ||
IMG_9, | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이미지들 관리해주는 방식 좋다!
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요기서 상단바 아이콘도 바꿔주면 좋을거 가태
|
||
const Header = () => { | ||
const { correctCard, difficulty } = useGlobalContext(); | ||
const spanRef = useRef(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useRef 사용 야무지다✨
<StyledHeader> | ||
<h1>⭐찌호를 맞춰주세요⭐</h1> | ||
<span ref={spanRef}> | ||
{correctCard.length} / {difficulty === 'Easy' ? 5 : difficulty === 'Normal' ? 7 : 9} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
나는 요거 switch문 갈겼는데 삼항연산자 사용하니 넘 깔꼼 ,,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
사실 switch 쓰는 것도 괜찮을지도!! 가독성은 둘 다 비슷한 것 같아
|
||
const StyledHeader = styled.header` | ||
width: 100vw; | ||
height: 200px; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요기만 px 사용한 이유는 뭘깡 ?! 궁금해용
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아아마...
rem은 최상위 요소 font-size를 따라가니까 어찌되었든 가변성이 있는 값이잖아!!!
그래서 header나 nav 같이 특정 고정 값들이 필요하다고 생각되는 곳에는 픽셀을 적는 것 같아!
}; | ||
const rotate = correctCard.includes(url) || openCard.some((x) => x.index === index); | ||
|
||
return <CardView rotate={rotate ? 'rotateY(0deg)' : 'rotateY(180deg)'} onClick={buttonOnclick} imgURL={imgURL} />; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
뒤집어지는 효과 삼항 연산자로 걸어준거 예쁘다✨
const ModalRenderer = ({ children }) => { | ||
return ReactDom.createPortal(children, document.querySelector('#modal')); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
children 사용하니까 더 명확하당
export const reducer = (state, action) => { | ||
switch (action.type) { | ||
case 'ADD_OPENCARD': | ||
return { | ||
...state, | ||
openCard: [...state.openCard, action.value], | ||
}; | ||
case 'CLEAR_OPENCARD': | ||
return { | ||
...state, | ||
openCard: [], | ||
}; | ||
case 'ADD_CORRECTCARD': | ||
return { | ||
...state, | ||
correctCard: [...state.correctCard, action.value], | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useContext랑 reducer는 일케 사용하는거구낭 형근이 코드 보구 많이 배운다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ㅋㅎㅋㅋ쿠ㅜ 리덕스도 이거랑 거의 구조가 비슷하니까 한 번 익혀두면 써먹기 좋아!! 나는 그랬어..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
7주차에 드디어 형근이의 코드를 이해할 수 있다ㅋㅋㅋㅋ
const getArray = () => { | ||
switch (difficulty) { | ||
case 'Easy': | ||
return shuffle(easyArr); | ||
case 'Normal': | ||
return shuffle(normalArr); | ||
case 'Hard': | ||
return shuffle(hardArr); | ||
default: | ||
return []; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
가독성 구웃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
코드 진짜 짱 깔끔,,
export default defineConfig({ | ||
plugins: [react(), image()], | ||
// base: '/HyeongGeunOh/', | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요게 그 vite 배포 중 생긴 오류 땜에 붙인 코드인가유?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
녜...근데도 성공 못한....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
또 많이 많이 배워갑니다
const context = useContext(Context); | ||
|
||
if (context === undefined) { | ||
throw new Error('useSelect must be used within a <ContextProvider />'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
햐 이런 에러 핸들링 너무 좋다
const getArray = () => { | ||
switch (difficulty) { | ||
case 'Easy': | ||
return shuffle(easyArr); | ||
case 'Normal': | ||
return shuffle(normalArr); | ||
case 'Hard': | ||
return shuffle(hardArr); | ||
default: | ||
return []; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
코드 진짜 짱 깔끔,,
const difficultyHandler = (e) => { | ||
setDifficulty(e.target.value); | ||
clearOpenCard(); | ||
clearCorrectCard(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이벤트 핸들러로 난이도 설정하고 clear opencard, correct card 깔끔하다!
setTimeout(() => { | ||
spanRef.current.classList.remove('bright'); | ||
}, 800); | ||
}, [correctCard]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useEffect로 spanRef에 bright클래스 추가하고 다시 제거하는 로직이구나 멋지다!
✨ 구현 기능 명세
기본 과제
✅
게임 난이도 선택
=> 구현 완료했습니다!
✅
정답 수 노출
=> 구현 완료했습니다!
✅
카드 선택
=> 열린 카드 / 쌍을 맞춘 카드를 구분하여 구현 완료했습니다!
✅
카드 배열 순서
=> src/utils/getRandomIndexArray.js 를 통해 구현 완료했습니다!
심화 과제
✅
애니메이션
=> 막 엄청 예쁜 애니메이션은 아니지만...구현 완료했습니다!
✅
theme
+styled-components
:: 적용=> 적용 완료했습니다!
✅
게임 초기화 버튼
=> 구현 완료했습니다!
✅
createPortal
=> 구현 완료했습니다!
🌼 PR Point
Context API 활용
src/context/reducer.js
전역으로 관리할 초기 상태와 상태를 변경할 수 있는 함수를 context로 생성해주고, reducer를 생성하여 상태 변경 로직을 담았습니다.
이때, useGlobalContext 커스텀 훅을 선언하여 생성한 context가 Provider 내부에 존재하는지 검증해주었습니다.
src/context/provider.jsx
전역 상태를 전달해줄 provider를 선언하고 value 값으로 초기 상태와 각 상태 변경 로직들을 담아주었습니다.
3d 애니메이션 적용
src/template/CardTemplate.jsx
카드 전체를 덮어주는 wrapper에서
perspective
속성을 통해 원근감을 적용했습니다.src/components/atom/CardView.jsx
각각의 카드 내부를 앞면, 뒷면으로 나눠주었고, 앞뒷면을 감싸는 컴포넌트에
transform-style: preserve-3d;
속성을 적용해주어 각 perspective 속성이 카드 내부 요소로 전달될 수 있도록 해주었습니다.또한 내부 카드들 중 뒷면에는 기본적으로
rotateY(180deg)
를 적용하고, 앞뒷면 모두에backface-visibility: hidden;
을 적용하여 카드의 뒤집히는 애니메이션을 구현하였습니다.타입 별 버튼 렌더링
src/styles/theme.js
공통으로 사용되는 버튼 스타일을 지정하여 ThemeProvider를 통해 전달될 수 있도록 했습니다.
src/components/atom/ButtonView.jsx
이후 버튼에서 공용 버튼 스타일을 적용해주었습니다.
src/components/ButtonView.jsx
buttonType을 통해 if 나 switch문을 사용하는 대신 하나의 컴포넌트 내에서 타입지정을 통한 렌더링 분기를 적용했습니다.
짝 맞출 시 애니메이션 적용
src/styles/bright.css
애니메이션을 생성한 뒤 클래스를 통해 관리할 수 있도록 해주었습니다.
src/components/Header.jsx
이후 점수 표기하는 곳에 useRef를 사용하여 class를 탈부착 하는 형식으로 특정 상황에서 애니메이션이 작동할 수 있도록 구현해주었습니다.
🥺 소요 시간, 어려웠던 점
8h
전체적으로 오랜 시간이 걸렸고, 초반에 일단 기능을 구현하는데 힘쓰고 이후에 리팩토링 하는 과정에서 디렉토리 구조를 미리 설계할걸 하는 후회가 조금 있었습니다. 이후에는 미리 생각하고 만드는 J 스러운 면모를 가지도록..노력해보겠습니다.
첫 리액트 과제였는데, 오랜만에 다양한 리액트 훅을 사용하니 리액트의 감사함을 많이 느낀 것 같아요. 물론 그만큼 훅 없이도 기능들을 구현할 수 있는 사람이 되어야 하겠지만요!
언제나 고민할 수 있는 포인트를 제공해주어 성장에 큰 발판이되는 과제들인 것 같습니다. 항상 질 좋은 과제 제공해주셔서 감사합니다 :)
🌈 구현 결과물
3주차 과제